//////// // // // // // /// // // // // //// // // //////// // // // // // // //// // // // /// // // // // /////// Pascal NewsLetter Issue #2 May, 1990 Editor: Pete Davis The Programmer's Forum BBS is the home of PNL. It can be reached in Washington, DC at (202)966-3647. Information is available through the following locations: FidoNet: Pete Davis@1:109/138 GEnie: P.DAVIS5 BitNet: HJ647C@GWUVM & UE356C@GWUVM InterNet: HJ647C@GWUVM.GWU.EDU & UE356C@GWUVM.GWU.EDU Table of Contents Introduction ........................... Page 3 (Pete Davis) Making the Point with Pointers ......... Page 5 (Pete Davis) Neat Use of Object Files ............... Page 16 (Craig Thurber) For Beginners .......................... Page 22 (Bob Gowans) Conclusion ............................. Page 29 (Pete Davis) Notice ................................. Page 32 (Pete Davis) Distribution List ...................... Page 33 (Pete Davis) Turbo Pascal is a registered trademark of Borland International 2 Introduction Well, school is over and it's time for the second issue of PNL. I would first like to thank Robert Garcia in Edinburgh (did I spell that right?) Texas. He was the first person to give me a response. His praise alone would have been enough for the second issue to come out. He also gave me the idea for an article on pointers for beginners. I had overlooked that, so here it is. Secondly, I would like to thank Craig Thurber, the author of 'Neat Use of Object Files' and Bob Gowans, the author of the 'For Beginners' column. I really liked the articles and learned something new. Thanks Craig and Bob, feel free to contribute any time. I would like to point out that I am really open to submissions. Please, if you write an article, send it to us. I can't guarantee when or if it will go in, but it can't hurt to try. It takes some of the load off of my shoulders. One subject that I would really like to see covered in PNL, is Object Oriented Programming in Turbo Pascal. This is one subject I will have to leave to others, at least for now, as I am not really fluent in it yet. So, if you're a hot-shot with OOP, please submit an article. It would be very beneficial to a lot of people, including me. 3 I would really just like to thank everyone that I've heard from. Your compliments, suggestions, and comments are what makes this worth doing. I hope to have the PNL going for as long as I'm computing. Oh yeah, and one last thing. The release of PNL might be a little sporadic. Maybe after a while I'll start setting some kind of time period up, but right now, it's whenever I get the time. I'm hoping to be able to do it more than once a month, if time allows. I really do enjoy writing this. Well, until the next issue, thanks, and please try to pitch in: be it an article, a suggestion, or just passing this file around to your local bulletin board. All of this helps. _Pete Davis 4 Making the Point with Pointers Those of you familiar with C are probably very comfortable with pointers. That's understandable, you can't program in C without pointers (well, you can, but not well). Well, those of us that started on Pascal have a little more trouble understanding them. Part of the problem is that pointers seem almost foreign to the ideas and methods of programming in Pascal. In fact, until getting involved in more advanced programming, one can usually get away without using pointers at all. So, why use pointers? Well, there are several reasons. For one, and probably most important, it gives you access to the heap, all that extra memory you have in a 640K machine that you normally can't use. In Turbo Pascal, you are limited to 64k for any single data structure. This is a pretty severe limitation when you are working with, say, a database, or a word processor. Secondly, there are quite a few structures that are more difficult to work with without pointers, for example, a binary tree. There are a multitude of structures that pointers make possible. Covering every single one of them would be almost impossible. To make things a little more reasonable, I will cover the basic concept of pointers, and then the most common use of them: The linked list. I will leave coverage of other structures to future releases of PNL. In PNL001, there was an article: Generic Structures in Turbo Pascal, which covered a simple stack, 5 using pointers. It was a more complicated version of a stack, actually, but the same ideas prevail for other structures. I will present a linked list with several operators. I will also include source code to the Linked List unit itself and then in the article on Sorting, I will include some sorting routines to manipulate our linked list. Think of a linked list as a chain. Each link in the chain contains some data. At the end of that link is another link with more data. You can add links to your chain and you can take them off. If you take a link out of the middle, you have to re- connect your two chains to make a single chain. This is the basic premise for linked lists. Depending on how you want your data ordered (if you even want it ordered) decides how you insert your data. If you want a stack, you always add a link at the beginning of your chain. If you want a queue, you always add a link at the end of your chain. If you want a non-ordered linked list, you could do either. If you want an ordered linked list, though, you have to go through your list, find out where your link goes, and insert it between two other links. (unless it's the lowest or highest value in the list) Below is a small diagram of a linked list. Following it is a short explanation. 6 Node 1 Node 2 Node 3 +----------+ +----------+ +----------+ | Data | +--->| Data | +--->| Data | | Item 1 | | | Item 2 | | | Item 3 | +----------+ | +----------+ | +----------+ | Pointer |----+ | Pointer |----+ | Pointer |-->NIL +----------+ +----------+ +----------+ Each node in our list contains two things: A Data Item, which the programmer can decide on: A record, a string, an integer, etc.. Any data type will do. The second item is a pointer. The pointer points to the location in memory of the next node in the list. The two nodes don't have to be anywhere near each other in memory, but as a programmer, they will appear to be right next to each-other. Notice the NIL in the pointer in Node 3. This is a reserved value in pascal that indicates that the pointer is pointing to nothing. In our case, it signifies the end of the list. Now, we are missing one item in our list, and that is the pointer to the beginning of the list. This is something that you must have, otherwise you won't know where in memory your list is. First, let's create our sample record and pointer: type Samp_Ptr = ^Samp_Rec; { A pointer to a Samp_Rec record } Samp_Rec = record { Our Samp_Rec record type } SampData : integer; { Data can really be anything } Next_Rec : Samp_Ptr; { Pointer to next item in list } end; 7 Ok, Samp_Ptr is a pointer to data of type Samp_Rec. You make a typed pointer by including the '^' before the data type that you want to point to; in this case Samp_Rec. Notice that Samp_Ptr is declared before Samp_Rec, yet Samp_Ptr is a pointer to type Samp_Rec. The reason for this is so that the Next_Rec pointer can be declared, making linked lists possible. Now, to help give us something to work with, I'll show the initialization procedure, and then go into a bit of explanation about how it works. procedure Init_Samp_List(var Head : Samp_Ptr); { notice in our initialization that a record of type Samp_Rec is never defined nor used! } begin Head := nil; end; First of all, notice that in our initialization we are passing a pointer of type Samp_Ptr, and not an actual record. It must also be passed as a variable parameter, as the variable Head will be given it's initial value and that value must return to the main program. The only code in this procedure is to assign the pascal reserved value of nil to Head. Head means the head of the list, or the first link in the list. nil is a variable name supplied by pascal which means that there is not value assigned to the variable. In our case, it means that our list is empty. 8 Now, I want to supply a simple insert procedure to insert a single value into the list. This will give us a little picture of how to manipulate our data with pointers. The insert procedure I am providing here inserts a value into the beginning of the list. In the Turbo Pascal Unit, enclosed, you will find three insert procedures: Insert_End, Insert_Begin, and Insert_In_Order. I'll leave Insert_Before, and Insert_After for you to write. They way they are supposed to work is that Insert_Before will insert a record right in front of the current record you are pointing to. To accomplish this, you need to pass two items: The head, so you can go through the list again to find out what the record is before the current record, and the current record, of course. Insert_After is a little easier, in all that needs to be passed is the current record. The record you insert should end up pointing to the record that was right after the current record, and the current record should end up pointing to the one you insert. One would rarely need this many insert procedures, in fact, one is usually enough. So, on with our Insert_Begin procedure: procedure Insert_Begin(var Head : Samp_Ptr; Data_Value : integer); var Temp : Samp_Ptr; { A temporary variable to work with } begin { Allocate memory for a Samp_Ptr } new(Temp); 9 { Temp will become the first record and Head will become the second record in the list. But, we have to do things kind of backwards, so first: Make head the second record } Temp^.Next_Rec := Head; { Now that Temp^.Next_Rec has a pointer to where the second record is, we can now change the value of Head so that it will be at the head of the list. } Head:= Temp; { Next we need to put the value in this first record, that the user has provided to us. } Head^.SampData := Data_Value; end; {All done} Here's what's going on: First of all, the new command is used to allocate some space on the heap for our data. The new procedure returns the memory location of this space in the variable Temp. Instead of directly using a Samp_Rec data type, we use the pointers Temp and Head to access the fields in our reserved space. To do this, the general construct is: POINTER^.FIELDNAME One can assign something to this place or receive a value already stored. For example, to find the contents of SampData for the first record in the list we could do the following. (Assume that OurInt was previously defined as an integer.) OurInt := Head^.SampData; or we could change the contents by writing: Head^.SampData := OurInt; The most important step and the one that seems to cause the most problems for programmers unfamiliar with pointers, is 10 maintaining and traversing the links in our list. Noticed what we did in our Insert_Begin procedure - If we are using a new list, then Head is going to have a value of nil : Head-> Nil First of all, we allocate some memory for the record and then assign the value of head to Temp^.Next_Rec : +----------+ | SampData | Temp -> | undefined| +----------+ | Next_Rec | | Nil | +----------+ Next we assigned Head to be equal to Temp: +----------+ Head -> | SampData | Temp -> | undefined| +----------+ | Next_Rec | | Nil | +----------+ After that, we had to assign the value to SampData. Suppose we passed the value of 4: +----------+ Head -> | SampData | Temp -> | 4 | +----------+ | Next_Rec | | Nil | +----------+ 11 That takes care of our first value, but what about the second value? How does that work? Well, if we follow the same steps as before, let's see where it leaves us. Let's say we're going to insert a value of 12 this time. First of all we need to allocate space and Temp will be pointing to that space, then we assign Temp^.Next_Rec to Head: +----------+ +----------+ | SampData | | SampData | Temp -> | undefined| +-----> | 4 | +----------+ | +----------+ | Next_Rec | | | Next_Rec | | Head |----+ | Nil | +----------+ +----------+ Now, we assign the value of Head = Temp. That will move Head to the beginning of the list. +----------+ +----------+ Head -> | SampData | | SampData | Temp -> | undefined| +-----> | 4 | +----------+ | +----------+ | Next_Rec | | | Next_Rec | | -------|----+ | Nil | +----------+ +----------+ Now we assign the value of Data_Value (12) to the SampData field. +----------+ +----------+ Head -> | SampData | | SampData | Temp -> | 12 | +-----> | 4 | +----------+ | +----------+ | Next_Rec | | | Next_Rec | | -------|----+ | Nil | +----------+ +----------+ 12 That just about does it for the insert procedure. It's a very difficult concept for beginners to understand and that's why I am supplying all of the diagrams. I want to make the concept of pointers themselves as clear as possible. Once you understand the concept, the different operations on them become easy. If at this point you still don't understand, I suggest that you reread from the top of the article and give it another try. If at that point you still don't understand, try putting it away for a day or two and try again. I find that putting a difficult concept away for a little while and coming back to it makes it easier to understand. Like the insert operations, the delete operations come in all shapes and sizes. The accompanying unit contains the following: Pop_First (for stack use), Pop_Last(for queue) and Delete_Here. Again, I will leave Delete_Before and Delete_After for you to write. With the three I provide, it should be fairly simple. These are more than enough for the typical linked list. The main problem with doing the delete is that you have to find out where you are in the list before you can take any action. If you want to delete the first node in the list, then you have to re-assign the Head of the list to the second item in the list. If you want to delete something from the end of the list, you need to make sure that the Next_Rec field is set to Nil in the last record. If you want to delete something in the middle of the list then you have to reconnect to second half of the list to what's left of the first half. 13 Using our first diagram: Node 1 Node 2 Node 3 +----------+ +----------+ +----------+ | Data | +--->| Data | +--->| Data | | Item 1 | | | Item 2 | | | Item 3 | +----------+ | +----------+ | +----------+ | Pointer |----+ | Pointer |----+ | Pointer |-->NIL +----------+ +----------+ +----------+ If we take out Node 2, we have to assign the pointer in Node 1 to point to Node 3. If we get rid of Node 3, we need to have the Pointer in Node 2 be nil. Node 1 Node 2 Node 3 +----------+ +----------+ +----------+ | Data | X--->| Data | X--->| Data | | Item 1 | X | Item 2 | X +->| Item 3 | +----------+ X +----------+ X | +----------+ | Pointer |--+-X | Pointer |----X | | Pointer |-->NIL +----------+ | +----------+ | +----------+ +------------------------+ This brings up the need for one more procedure provided in pascal, and that's the dispose procedure. The dispose procedure returns whatever space you have allocated back to the heap so that it can be reused. You don't always have to do that, but if you are working with a lot of data and you get rid of links without using the dispose procedure, you are more likely to run out of heap memory. I will let you look at the source code for an example of the dispose procedure. I'm going to have to keep myself from including more code examples in the magazine, and instead let you see the unit that is included with this issue. It has all the necessary procedures and functions, and then some. Each one has a description as to 14 it's function. I don't feel that further explanation here would be beneficial. In other words, I'm out of breath and thought. I don't know what else I could tell you. I hope this article has been helpful, and if anyone feels that I've missed something important, I'll do a follow-up article on it. I will be showing other uses of pointers in other issues, but it is unlikely that I will keep it this basic, unless demand keeps things at this level. 15 NEAT USE OF OBJECT FILES by Craig Thurber Not long ago I wanted to do something simple: include a downloadable soft font file in a compiled Pascal .EXE file. This seemed like an easy thing to do, but alas, I could not find anything in my documentation or reference books that gave an indication of how to do it. It wasn't long before some of the fine users of this language pitched in and provided an answer to the problem. The answer has proven to be a neat use of object files. The inclusion of text or other types of files in the .EXE forms has a number of advantages, the most notable of which is a very quick access to what might otherwise be a separate disk file. Since the equivalent of the disk file is already loaded into memory, there is no need to wait for a floppy disk file to be accessed. The method and some examples are presented below. Many thanks to Juan Jimenez for both his insights into this problem and his patients in providing an answer for which I had no more questions. Juan answered the message that I posted in the GEnie Borland Roundtable. If you are interested in a very fine service, please consider this one*. External Procedure Calls ------------------------ External procedures can be declared and called in the Pascal 16 language. The user manual suggests that this capability was included in the language primarily for inclusion of assembly language routines in the compiled versions of Pascal programs. However, the call to an external procedure can also be used to move the contents of a text or other type file to a Pascal pointer location, and then to perform standard Pascal operations with the data that resides at that pointer location. Declaration of an external procedure call is made with the following statement in a Pascal program or unit: procedure HelloJuan; external; {$L HELLO.OBJ} In the above example, the external file named HELLO.OBJ will be included in the compilation of the .EXE file. The {$L} compiler directive is the local symbol information directive. Note that this compiler directive is ignored if the Debug Information setting {$D-} is set to off. The overall effect of this declaration is that the external object file named HELLO.OBJ is recorded in the .TPU or .EXE file at the time of compilation. While this inclusion will increase the size of these files, it does not slow program execution. Creation of Object Files ------------------------ Object files are created with the BINOBJ.EXE utility that is provided with Turbo Pascal. The procedure involves invoking the BINOBJ.EXE procedures with a designated file for conversion and 17 an external name to give to the file. In the case shown above, the test file HELLO.TXT would be converted to the object file HELLO.OBJ having the external procedure call HelloJuan with the following command (assuming the given drives and directories): C:\TP\BINOBJ A:\HELLO.TXT A:\HELLO.OBJ HELLOJUAN When creating object files, keep track of the original file size. You will need it later when you invoke them in a Pascal procedure. Using the External Procedure ---------------------------- Suppose that you started by declaring the above procedure after converting the file HELLO.TXT to the object file HELLO.OBJ. The original text file contained the statement "Hello, Juan.", which is 13 characters long. After conversion to an object file, be sure not to confuse the byte size of the object file with the size of the original text file; it is the size of the original file that you will need while writing the Pascal code. Suppose also that the objective of your programming is to send the statement "Hello, Juan." from the compiled .EXE file to the printer. Here is the code that will do this, as a complete program. Each statement in the program is explained below. program Hello; uses Printer; procedure HelloJuan; external; {$L+ HELLO.OBJ} 18 var PtrStr : Pointer; OutString : String; begin PtsStr := @HelloJuan; Move(PtrStr^,OutStr[1],13); OutStr[0] := Chr(11); Writeln(Lst,OutStr) end. The result of running this file will be printing the words "Hello, Juan" on the printer that is located at LPT1. As nice a fellow as Juan is, I don't suppose that making your printer say hello to him is very useful to you. So here is another example. Suppose you want a full screen of text to appear instantly. You have written programs that make a call to an external file and have watched them slowly write one line at a time down the screen; you have had enough of this and you want the speed that Pascal normally shows. Well, this could be the answer. Write your text file, note the length of it (I'll use 2000 here) and then change the above program as shown below. For purposes of this article, I have assumed that the file names and external declarations are the same; the only difference is that you are now writing a nice letter to Juan and you want it to appear on the screen very quickly. Here is the procedure code that will do it: procedure HelloJuan; external; {$L HELLO.OBJ} const Size = 2000; 19 var PtrStr : Pointer; OutStr : Array[1..2000] of Char; Index : Integer; begin PtrStr := @HelloJuan; Move(PtrStr^,OutStr[1],Size); For Index := 1 to Size do Write(OutStr[Index]) end; What's That Code All About? --------------------------- Here is what the coding is all about: Variable declarations: PtrStr is a generic pointer. It is used to mark the starting location of the compiled external file. OutStr is an array that is large enough to hold the contents of the externally declared procedure. Index is a simple counter that is used to track the feeding of each character of the compiled external file to the screen. PtrStr := @HelloJuan; : This statement moves the pointer to The start of the procedure that was named HelloJuan during the conversion of the text file to an object file. Move(PtrStr^,OutStr[1],Size);: This statement moves the number of bytes specified by Size from the starting location specified by PtrStr^ to the first element of the array OutStr. 20 For Index ... do : This loop dumps the array OutStr to the screen one element at a time. The resulting screen dump will appear exactly as the original text file was written. What Else Does It Do? --------------------- The conversion of files to object files and inclusion of them in the executable form of a program offers a wide variety of opportunities for programmers. In principle, any file that you can present on the screen or printer can be converted to an object file and then included in the .EXE file during compilation. When the procedure is called using the above techniques, the results will be very quick and will be an exact duplicate of what you would get by other means. So if you want to have a fast way of accessing help files, graphics or other files, give the method a try. * A GEnie account can be obtained by calling 1-800-638-9636. 21 For Beginners By Bob Gowans Where to start? A good question - the beginner's column is aimed at people with little or no programing experience of Pascal and will start at a very basic level but will graduate (hopefully) to more complicated programming routines as our confidence in the use of Pascal increases. With this in mind I would appreciate any feedback on my articles - suggestions, constructive criticism and especially any neat programing tricks that beginners would find useful. I will give details on contact addresses at the end of this article. Pascal has to be taught in a way that encourages good programing. As a high-level language it is structured in this way and can allow the Pascal programer to present his programs in a manner of clarity that is almost unparalleled by other high-level languages. So if you have just bought the latest version of your favorite Pascal compiler and your fingers are itching to get at the keyboard to write that ultra program you have always wanted to produce to impress your friends, wife, boss? Then stop! Good programs take a lot of thought and planning before you reach the actual coding stage. In fact, an English language equivalent of your program should first be produced, showing step by step what your program does. Moreover this English language version should be able to make clear, to 22 non-programers, exactly what your program is going to do. This may not be essential for the relatively small programs which we will encounter at this stage but it is an invaluable technique when writing large programs (such as the impressive ultra program) and as an aid to problem solving. It is well worth while getting into the habit of using this method known as TOP-DOWN design to plan you programs. In future articles it is hoped that I will be able to introduce this method but meanwhile lets get back to those itching fingers and get on with some program writing. The programs given as examples are standard Pascal, that is they should compile using any Pascal compiler, however I have only used Turbo Pascal V4 to try them out and test them. Here is a simple but complete Pascal program: program hello_there; { This is our first program } begin write('Hello'); writeln(' my name is Bob'); write('How are you?') end. Lets break this program down to it's component parts and examine each part in turn. The program starts with the word program followed by a space followed by the program name. In this case the name is hello_there but subject to some rules, it could be anything we chose, however it is good programing practice to chose a name that is relevant to what the program does. Such names are given the term IDENTIFIERS. Rules for identifiers: 23 1) An identifier must begin with a letter. 2) They may then consist of letters and digits, upper or lowercase letters are treated as identical. 3) They can contain embedded underscore characters to improve readability as has been done in our example program identifier - hello_there. 4) They can be of any length but generally speaking the compiler will ignore anything following the first 8 identifier characters. Examples of Identifiers: accounts A386XT Income_Tax BUDGET1990 Try this self-test, the answers are given at the end of the article. Which of the following are valid identifiers: a) FirstRun b) Mississippi c) Locust12 d) George Washington e) Program f) 123go g) accounts.1990 24 By the way, reserved words, that is words that the Pascal language itself uses, cannot be used as valid identifiers. The complete list of Pascal reserved words should be found in your manual or any decent book on Pascal. Going back to our program, the program heading (Program hello_there;) has a semi-colon at the end of the line. The program heading does not contain any actual commands it simply marks the beginning of the program. Program commands come between the Pascal reserved words begin and end, they are often referred to as the statements part of the program and each statement line is separated by a semi-colon(;). The statements part of the program contains a series of instructions for the computer to execute. Our example program contains statements designed to write output to the screen. To write a line of output the standard output procedure writeln, the form is writeln('textout'). Writeln and write are very similar in what they do but writeln has the advantage of performing a carriage return so your next writeln statement would write out text on a new line. Try the program and make sure you understand the differences between write and writeln. Note that each statement in the statements part is separated by a semi-colon except the one preceding the reserved word end and that the final end in the program is followed by a period. Finally on the 25 program heading line you will have noticed that there is a comment in curly brackets. You can place comments at strategic points in your program to add clarity. Comments will help you when you want to amend you programs after you have not used them for some time they will show what your intention was at the time you wrote the program, something you may have forgotten as time goes by. The rule is you can place comments at relevant points in the program as long as they are placed within curly brackets. Here are some more examples for you to try: program Name_and_address; { writes to the screen your name and address } begin writeln('My Initials Surname'); writeln('Department of Computer Science'); writeln(' The University'); { note the use of spaces for output } writeln(' City'); writeln(' Country') end. Writeln is handy for inserting blank lines so that your text output looks better program nice_lines; begin writeln('Line one'); writeln; { inserts a blank line } writeln('Line three') end. Just to get you thinking, write a Pascal program that would produce the following output to the screen: 'How many times have I told you, don't do that'; she said. 26 Clue - watch the quotation marks! TIP - If you are using Turbo Pascal there is a neat routine provided to clear the screen. It can be implemented as follows: program clear; uses crt; { this must be here and is for turbo pascal only } begin clrscr; { turbo pascal clear screen routine } ........... ........... end. I hope you have found this article helpful in the next issue I hope to discuss variable types found in Pascal, more about top-down design and provide more tips. I will also provide a solution to the exercise. In case you cannot wait and are pulling your hair out in frustration you can contact me at the following Email addresses for the solution. I would also be pleased to help beginners with Pascal programing problems as well. JANET - MCGDRKG@UK.AC.MCC.CMS INTERNET - MCGDRKG%MCC.CMS.AC.UK@CUNYVM.CUNY.EDU EARN/BITNET - MCGDRKG%MCC.CMS.AC.UK@UKACRL I would really appreciate useful routines for publication and especially nice little tricks like the clear-screen routine for turbo pascal which would be of benefit to users at this level. 27 Thanks for your attention - Bob Gowans. Self Test Answers a) Valid. b) Valid c) Valid d) Invalid - there is a space character. e) Invalid - program is a Pascal reserved word. f) Invalid - does not start with a letter. g) Invalid - Pascal identifiers do not allow a period. 28 Conclusion Well, I have to say, I'm much happier with the second issue of PNL. I'm glad I found the time to include some code examples. I feel it is important to have something substantial for the users to work with. I would especially like to thank Craig Thurber and Bob Gowans for their help by including very well written and useful articles. I hope that in the future they, and others, will contribute more. It not only gives readers more than one point of view in programming, but it also takes a big load off of my shoulders. I had originally planned an article on sorting routines for this issue, but because of time constraints I've been finding it very difficult to proceed. Instead of delaying the release of this issue further, I have decided to go ahead and release this issue and try to put the sorting article in a future issue. I would be a liar if I said I think the code I have provided is fool-proof. I've tested it, but I might have overlooked something. If you do find a bug in the code I've provided, please let me know and I will include code fixes in following issues. My original plan was to have more than one issue of PNL out a month, but unless I start getting a lot of article contributions, that's going to be a difficult thing to 29 accomplish. I'll tell you one thing that would be really nice to have is reviews written by users. If you would like to review libraries and toolkits, feel free to send those reviews in. I am also considering a column called 'Bits and Pieces' which will have a bunch of small tips and techniques in pascal that are too small to deserve articles by themselves, but which would be useful. Another column I would like to include is a reader mail column for comments and Q & A. I am developing a rather large distribution list and know I will be racking up pretty hefty phone bills if it gets much larger, so for the moment, here are the plans. I will only take a few more people by node address on the distribution list. It's much easier for me to send via BitNet, so I'll be taking BitNet addresses until it gets too overbearing. If you have a mainframe account that is on BitNet, you can pick it up from Simtel20 either by using either of the following: TELL LISTSERV AT NDSUVM1 /PDGET PD:PNLxxx.ZIP or TELL LISTSERV AT RPIECS /PDGET PD:PNLxxx.ZIP where xxx is the issue #. (These are CMS commands. If you're on a Vax, the commands may differ slightly.) It is also available on GEnie. I will start putting the FidoNet addresses, State, and Area Code of people on the distribution list. Perhaps one of them 30 will be within local calling range of you. What would be really nice, is if some people out there with BitNet accounts in major cities would offer to receive a copy and spread it around their cities for me. It's really difficult getting a good distribution, but I'll work at it. Hopefully after a while distribution will take care of itself. i.e. the PNL gets popular enough that it gets spread around well. Well, that just about does it for the second issue of PNL. Hope it's been useful, and like I say and say and say, please submit articles and send suggestions. This newsletter is for the readers, not me. _Pete Davis 31 The Pascal NewsLetter is Copyrighted by Peter Davis. It may be freely distributed in un-modified form, but no charge whatsoever may be incurred on the recipient. The Pascal NewsLetter can be obtained from the following locations: GEnie : General Electric Network for Information Exchange. It is located in the IBMPC filelist. Simtel: Internet address: 26.2.0.74 or Simtel20.ARPA It is located in the directory. Programmer's Forum : This is the home of the PNL. Each issue can be found in the MAG directory from the main area. The number is on the title page. If you would like to receive back issues of PNL directly from me, send a diskette and $2.00 for shipping. Don't forget to include your address. Send your order to: Peter Davis 4851 Brandywine St. NW Washington, DC 20016 If you are a SysOp that will regularly carry PNL and would like to have your bulletin board listed as such, here, send me a message either by postal mail or at one of the electronic addresses given on the title page, with your bulletin board's name, phone number, your name, maximum baud rate, and a description of up to 60 characters of your bbs. 32 Distribution List The following is the phone numbers to bulletin boards known to carry PNL. If you would like your bulletin board's name and number added to or deleted from this list, please send me a message at one of my many addresses. The Programmer's Forum ................. Phone: (202) 966-3647 The Programmer's Forum is the home of the PNL. The Bored .............................. Phone: (512) 303-0471 Classic City ........................... Phone: (404) 548-0726 Theive's World ......................... Phone: (713) 463-8053 Hippocampus ............................ Phone: (203) 484-4621 Rogers State College BBS ............... Phone: (918) 341-8982 The Foxtrot BBS ........................ Phone: (404) 793-2673 33